package org.com.windoweasyconstructor;

import java.awt.Dimension;
import java.awt.event.ActionListener;
import java.util.HashMap;
import java.util.Iterator;

import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.KeyStroke;

public class Menu extends JMenuBar {
	
	private static final long serialVersionUID = -1938793099713621314L;
	
	/**
	 * Contém todas as instâncias de <code>JMenu</code> criadas em tempo de execução e as
	 * armazena para alterações e configurações manuais.
	 */
	private HashMap<String,JMenu> mapJMenus = new HashMap<String,JMenu>();
	
	/**
	 * Função semelhante à de <code>mapJMenus</code>, porém este <code>HashMap</code> guarda
	 * um outro <code>HashMap</code> contendo os itens de menu de acordo com a <b>key</b> relativa
	 * ao nome do <code>JMenu</code>.
	 */
	HashMap<String,HashMap<String,JMenuItem>> mapJMenuItens = new HashMap<String, HashMap<String,JMenuItem>>();
	
	/**
	 * Construtor padrão de <code>Menu</code>.
	 *
	 */
	public Menu() {
		
	}
	
	/**
	 * Adiciona uma série de menus à barra de menu. Para isso, passa-se um <code>Iterator</code> contendo
	 * <code>String</code>s que representam o nome do menu a ser visualizado na interface gráfica.
	 * 
	 * @param itMenus - <code>Itetaror</code>
	 */
	public void addJMenus(Iterator<String> itMenus, Iterator<String> itMnemonic) {
		Iterator<String> it = itMenus;
		//enquanto houver nomes no Iterator
		while (it.hasNext()) {
			String titulo = it.next();								//armazena o nome (titulo do menu)
			JMenu menu = new JMenu(titulo);							//cria o JMenu a ser adicionado
			menu.setMnemonic(itMnemonic.next().charAt(0));
			this.add(menu);											//adiciona o JMenu à barra de menu
			mapJMenus.put(titulo, menu);							//adiciona o JMenu ao HashMap responsável por manter
																	//as referências aos menus
		} //fim do while
	} //fim de addJMenus
	
	/**
	 * Recebe o nome do menu a serem adicionados os itens de menu e em seguida faz a
	 * adição de todos eles. Caso o nome do menu esteja incorreto ou não exista no
	 * <code>HashMap</code> de <code>JMenus</code> (mapJMenus) o método lança uma
	 * <code>NullPointerException</code>.
	 * 
	 * @param menu
	 * @param itens
	 * @throws NullPointerException
	 */
	public void addJMenuItems(String menu, Iterator<String> itens, Iterator<KeyStroke> itAccelerator) throws NullPointerException {
		//cria um HashMap interno para ser adicionado posteriormente á mapJMenuItens
		HashMap<String,JMenuItem> mapItens = new HashMap<String,JMenuItem>();
		Iterator<String> it = itens;
		
		//teste se há o menu solicitado pela String menu
		if (!mapJMenus.containsKey(menu)) {
			String descricaoNullPointer = "O menu '" + menu + "' não existe.";
			throw new NullPointerException(descricaoNullPointer);
		} //o método só continua daqui se o bloco if não foi executado
		
		//busca o menu solicitado
		JMenu jMenu = this.getJMenu(menu);
		
		//inicia a inserção dos itens
		while (it.hasNext()) {
			String titulo = it.next();								//armazena o titulo do item de menu
			JMenuItem menuItem = new JMenuItem(titulo);				//cria o item de menu
			menuItem.setPreferredSize(new Dimension(300,25));

			if (titulo.equals("")) {								//se o titulo for fazio, significa a inserção de um separador de menu
				jMenu.addSeparator();								//adiciona o separador
				continue;											//pula o restante do while e continua se houver novos itens
			} else {
				menuItem.setAccelerator(itAccelerator.next());		//cria um accelerator (ctrl+tecla) ou (alt+tecla)
			}
			
			jMenu.add(menuItem);									//adiciona o item ao menu solicitado
			mapItens.put(titulo, menuItem);							//adiciona o item ao HashMap interno 
		}
		mapJMenuItens.put(menu,mapItens);							//adiciona o titulo do menu e o HashMap interno de itens
																	//ao HashMap responsável por mantê-los em tempo de execução
	} //fim de addJMenuItems
	
	/**
	 * Adiciona uma série de eventos em lote, de acordo com a <code>String</code> menu, e dois
	 * <code>Iterator</code>s. Um contendo os itens e o outro os eventos.<br><br>
	 * 
	 * Vale ressaltar que o número de elementos nos dois iterators deve ser o mesmo, pois os eventos
	 * serão adicionados na mesma ordem que forem lidos os elementos de <code>itens</code>. Exceto quando
	 * um elemento de <code>itens</code> for uma <code>String</code> vazia. Isto permite que o desenvolvedor
	 * utilize o mesmo <code>Iterator</code> usado no método <code>addJMenuItems</code>, caso queira
	 * configurar eventos para todos os itens desse menu.<br><br>
	 * 
	 * Para este método, não foram configuradas as exceções para ser mais claro em como ficaria a
	 * adição de eventos. Mas o ideal é que se tratem essas exceções como no método <code>addJMenuItems</code>.
	 * 
	 * @param menu
	 * @param itens
	 * @param eventos
	 */
	public void addEventos(String menu,Iterator<String> itens,Iterator<ActionListener> eventos) {
		HashMap<String,JMenuItem> map = mapJMenuItens.get(menu);
		while (itens.hasNext()) {
			String item = itens.next();								//armazena o item
			if (item.equals("")) {									//se for um separador de menu, o while passa para o próximo
																	//item, isso é, se o mesmo existir no Iterator
				continue;
			}
			JMenuItem menuItem = map.get(item);						//recupera o JMenuItem
			menuItem.addActionListener(eventos.next());				//adiciona o evento ao mesmo
		}	
	}
	
	/**
	 * @param titulo
	 * @return <code>JMenu</code> referente ao título passado.
	 */
	public JMenu getJMenu(String titulo) {
		return mapJMenus.get(titulo);
	}
	
	/**
	 * @param menu
	 * @param item
	 * @return <code>JMenuItem</code> referente ao item passado.
	 */
	public JMenuItem getJMenuItem(String menu, String item) {
		HashMap<String,JMenuItem> map = mapJMenuItens.get(menu);
		return map.get(item);
	}
}